// --------------------------------------------------------------------
// Copyright (c) 2005 by Terasic Technologies Inc. 
// --------------------------------------------------------------------
//
// Permission:
//
//   Terasic grants permission to use and modify this code for use
//   in synthesis for all Terasic Development Boards and Altrea Development 
//   Kits made by Terasic.  Other use of this code, including the selling 
//   ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Terasic provides no warranty regarding the use 
//   or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Terasic Technologies Inc
//                     356 Fu-Shin E. Rd Sec. 1. JhuBei City,
//                     HsinChu County, Taiwan
//                     302
//
//                     web: http://www.terasic.com/
//                     email: support@terasic.com
//
// --------------------------------------------------------------------
//
// Major Functions:i2c controller
//
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
//   Ver  :| Author            :| Mod. Date :| Changes Made:
//   V1.0 :| Joe Yang          :| 05/07/10  :|      Initial Revision
// --------------------------------------------------------------------
module speaker_i2c_controller (
	CLOCK,
	I2C_SCLK,//I2C CLOCK
 	I2C_SDAT,//I2C DATA
	I2C_DATA,//DATA:[SLAVE_ADDR,SUB_ADDR,DATA]
	GO,      //GO transfor
	END,     //END transfor 
	W_R,     //W_R
	ACK,      //ACK
	RESET
);
	input  CLOCK;
	input  [23:0]I2C_DATA;	
	input  GO;
	input  RESET;	
	input  W_R;
 	inout  I2C_SDAT;	
	output I2C_SCLK;
	output END;	
	output ACK;


reg SDO;
reg SCLK;
reg END;
reg [23:0]SD;
reg [5:0]SD_COUNTER;

wire I2C_SCLK=SCLK | ( ((SD_COUNTER >= 4) & (SD_COUNTER <=30))? ~CLOCK :1'b0 );
wire I2C_SDAT=SDO?1'bz:1'b0 ;

reg ACK1,ACK2,ACK3;
wire ACK=ACK1 | ACK2 |ACK3;

  //--I2C COUNTER
  always @(posedge CLOCK)begin
    if (RESET)
      SD_COUNTER <= 6'b111111;
    else
      begin
        if (!GO)
          SD_COUNTER <= 6'd0;
        else
          if (SD_COUNTER < 6'b111111) SD_COUNTER <= SD_COUNTER + 6'b1;
        end
      end
  //----

  always @(posedge CLOCK)
    begin
      if (RESET)
        begin
          SCLK <= 1'b1;
          SDO  <= 1'b1;
          ACK1 <= 1'b0;
          ACK2 <= 1'b0;
          ACK3 <= 1'b0;
          END  <= 1'b1;
        end
      else
        case (SD_COUNTER)
          6'd0:
            begin
              ACK1 <= 1'b0;
              ACK2 <= 1'b0;
              ACK3 <= 1'b0;
              END  <= 1'b0;
              SDO  <= 1'b1;
              SCLK <= 1'b1;
            end

          //start
          6'd1:
            begin
              SD  <= I2C_DATA;
              SDO <= 1'b0;
            end

          6'd2: SCLK <= 1'b0;

          //SLAVE ADDR
          6'd3: SDO  <= SD[23];
	6'd4  : SDO<=SD[22];
	6'd5  : SDO<=SD[21];
	6'd6  : SDO<=SD[20];
	6'd7  : SDO<=SD[19];
	6'd8  : SDO<=SD[18];
	6'd9  : SDO<=SD[17];
	6'd10 : SDO<=SD[16];	
	6'd11 : SDO<=1'b1;//ACK

	//SUB ADDR
	6'd12  : begin SDO<=SD[15]; ACK1<=I2C_SDAT; end
	6'd13  : SDO<=SD[14];
	6'd14  : SDO<=SD[13];
	6'd15  : SDO<=SD[12];
	6'd16  : SDO<=SD[11];
	6'd17  : SDO<=SD[10];
	6'd18  : SDO<=SD[9];
	6'd19  : SDO<=SD[8];
	6'd20  : SDO<=1'b1;//ACK

	//DATA
	6'd21  : begin SDO<=SD[7]; ACK2<=I2C_SDAT; end
	6'd22  : SDO<=SD[6];
	6'd23  : SDO<=SD[5];
	6'd24  : SDO<=SD[4];
	6'd25  : SDO<=SD[3];
	6'd26  : SDO<=SD[2];
	6'd27  : SDO<=SD[1];
	6'd28  : SDO<=SD[0];
	6'd29  : SDO<=1'b1;//ACK

	
	//stop
    6'd30 : begin SDO<=1'b0;	SCLK<=1'b0; ACK3<=I2C_SDAT; end	
    6'd31 : SCLK<=1'b1; 
    6'd32 : begin SDO<=1'b1; END<=1; end 

endcase
end



endmodule
